package com.casework

import org.joda.time.LocalDate

class SearchController {
    def springSecurityService
    def searchService

    def search = { SearchCommand command ->

        SearchQuery.cloneThe(command, springSecurityService.currentUser)
        Closure searchClosure = getSearchClosure(command)

        if (command.cases) {
            def c = LegalCase.createCriteria()
            def cases = c.listDistinct(searchClosure)

            cases = handleNaceForLegalCase(command, cases)
            cases = handleCompetitionConncern(command, cases)
            cases = handleFirmNamesForLegalCase(command, cases)
            if (command.textQuery) {
//                cases = cases.intersect(searchService.searchForLegalCases(command.textQuery)).unique().sort {LegalCase a, LegalCase b -> b?.ecNumber <=> a?.ecNumber}
                def legalCases = searchService.searchForLegalCases(command.textQuery)
                cases =legalCases.intersect(cases).unique()
            }

            def results = cases
            if (!command.viewAll) {
                int offset = params.offset?.toInteger() ?: 0
                int max = offset + 10 > cases.size() ? cases.size() : offset + 10
                results = cases.subList(offset, max)
            }

            render model: [legalCaseInstanceList: results,
                    legalCaseInstanceTotal: cases.size()], view: 'listLegalCases'
        } else {
            def m = Measure.createCriteria()
            def measures = m.listDistinct(searchClosure)

            measures = handleNaceForMeasures(command, measures)
            measures = handleCompetitionConncern(command, measures)
            measures = handleFirmNamesForMeasures(command, measures)
            if (command.textQuery) {
//                measures = measures.intersect(searchService.searchForMeasuers(command.textQuery)).unique().sort {Measure a, Measure b -> a?.legalCase?.decisionDate <=> b?.legalCase?.decisionDate}
                def newMeasure = searchService.searchForMeasuers(command.textQuery)
                measures = newMeasure.intersect(measures).unique()
            }


            def results = measures
            if (!command.viewAll) {
                int offset = params.offset?.toInteger() ?: 0
                int max = offset + 10 > measures.size() ? measures.size() : offset + 10
                results = measures.subList(offset, max)
            }

            render model: [measureInstanceList: results,
                    measureInstanceTotal: measures.size()], view: 'listMeasures'
        }
    }

    private Closure getSearchClosure(SearchCommand command) {
        def searchClosure = {
            if (command.cases) {
                if (command.ecNumber) {
                    eq('ecNumber', command.ecNumber)
                }
                if (command.fromDecisionYear) {
                    def startOfYear = new LocalDate(command.fromDecisionYear, 1, 1)
                    ge('decisionDate', startOfYear)
                }

                if (command.toDecisionYear) {
                    def endOfYear = new LocalDate(command.toDecisionYear, 12, 31)
                    le('decisionDate', endOfYear)
                }

                if (command.phase) {
                    inList('phase', command.phase)
                }

                if (command.relativeToSO) {
                    inList('relativeToSO', command.relativeToSO)
                }

                measures {
                    if (command.clusterSale) {
                        inList('clusterSale', command.clusterSale)
                    }
                    if (command.alternativeRemedy) {
                        inList('alternativeRemedy', command.alternativeRemedy)
                    }
                    if (command.purchaserCriterias) {
                        inList 'purchaserCriteria', command.purchaserCriterias
                    }
                    if (command.originOfDivestment) {
                        inList 'originOfDivestment', command.originOfDivestment
                    }
                    measureClassification {
                        if (command.classification) {
                            inList 'measureClassification3', command.classification.split(',')
                        }
                    }
                }
                order 'ecNumber', 'desc'
                cache true
            } else {
                if (command.clusterSale) {
                    inList('clusterSale', command.clusterSale)
                }
                if (command.alternativeRemedy) {
                    inList('alternativeRemedy', command.alternativeRemedy)
                }
                if (command.purchaserCriterias) {
                    inList 'purchaserCriteria', command.purchaserCriterias
                }
                if (command.originOfDivestment) {
                    inList 'originOfDivestment', command.originOfDivestment
                }
                measureClassification {
                    if (command.classification) {
                        inList 'measureClassification3', command.classification.split(',')
                    }
                }
                createAlias 'legalCase', 'c'
                if (command.ecNumber) {
                    eq('c.ecNumber', command.ecNumber)
                }
                if (command.fromDecisionYear) {
                    def startOfYear = new LocalDate(command.fromDecisionYear, 1, 1)
                    ge('c.decisionDate', startOfYear)
                }

                if (command.toDecisionYear) {
                    def endOfYear = new LocalDate(command.toDecisionYear, 12, 31)
                    le('c.decisionDate', endOfYear)
                }


                if (command.phase) {
                    inList('c.phase', command.phase)
                }

                if (command.relativeToSO) {
                    inList('c.relativeToSO', command.relativeToSO)
                }
                order 'c.decisionDate', 'desc'
                cache true
            }
        }
        return searchClosure
    }

    private Collection handleCompetitionConncern(SearchCommand command, Collection col) {
        if (command.competitionConcern) {
            col = col.findAll { command.competitionConcern.contains(it.competitionConcern.toString())}
            }
        return col
    }

    private ArrayList handleNaceForMeasures(SearchCommand command, List<Measure> measures) {
        if (command.shortNace) {
            def naces = Nace.withCriteria {
                naceCategory {
                    inList 'shortDescription', command.shortNace
                }
                cache true
            }
            def nacesWithCases = []

            naces.each {
                nacesWithCases.addAll(LegalCaseNaceFullDescription.findAllByDescription(it)*.legalCase)
            }

            def output = []
            measures.each { Measure measure ->
                if (nacesWithCases.contains(measure.legalCase)) {
                    output << measure
                }
            }
            measures = output
        }
        return measures
    }

    private Collection<LegalCase> handleNaceForLegalCase(SearchCommand command, Collection<LegalCase> cases) {
        if (command.shortNace) {
            def naces = Nace.withCriteria {
                naceCategory {
                    inList 'shortDescription', command.shortNace
                }
                cache true
            }
            def nacesWithCases = []

            naces.each {
                nacesWithCases.addAll(LegalCaseNaceFullDescription.findAllByDescription(it)*.legalCase)
            }
            cases = cases.intersect(nacesWithCases).unique()
        }
        return cases
    }

    private Collection<Measure> handleFirmNamesForMeasures(SearchCommand command, Collection<Measure> measures) {
        if (command.firmNames && command.firmNames?.split(', ')) {
            def firms = Firm.withCriteria {
                inList 'name', command.firmNames.split(', ')
                cache true
            }

            def legalCases = LegalCaseFirm.findAllByFirmInList(firms)*.legalCase
            def output = []
            measures.each { Measure measure ->
                if (legalCases.contains(measure.legalCase)) {
                    output << measure
                }
            }
            measures = output
        }
        return measures
    }

    private Collection<LegalCase> handleFirmNamesForLegalCase(SearchCommand command, Collection<LegalCase> cases) {
        if (command.firmNames && command.firmNames?.split(', ').size() > 0) {
            def firms = Firm.withCriteria {
                inList 'name', command.firmNames.split(', ')
                cache true
            }

            def legalCases = LegalCaseFirm.findAllByFirmInList(firms)*.legalCase
            cases = cases.intersect(legalCases).unique()
        }
        return cases
    }
}

class SearchCommand {
    boolean cases = true
    String ecNumberStr
    Integer fromDecisionYear
    Integer toDecisionYear
    List phaseStr
    List relativeToSOStr
    List clusterSaleStr
    List alternativeRemedyStr
    List purchaserCriteriaStrs
    List originOfDivestmentStrs
    List shortNace
    List competitionConcern
    String firmNames
    String classification
    boolean viewAll = false
    String textQuery

    Long getEcNumber() {
        if (ecNumberStr) {
            ecNumberStr = ecNumberStr.replace('M.', '')
            ecNumberStr = ecNumberStr.replaceAll(' ', '')
            try {
                return ecNumberStr.toLong()
            } catch (e) {
                return null
            }

        }
        return null
    }


    String toString() {
        """
        AlternativeRemedy: ${alternativeRemedyStr}, ${getAlternativeRemedy()}
        ClusterSale: ${clusterSaleStr}, ${getClusterSale()}
        relativeToSO: ${relativeToSOStr}, ${getRelativeToSO()}
        """
    }


    List getClusterSale() {
        def criterias = []
        clusterSaleStr.each {
            criterias << YesNoNA.fromName(it)
        }
        return criterias
    }

    List getAlternativeRemedy() {
        def criterias = []
        alternativeRemedyStr.each {
            criterias << YesNoNA.fromName(it)
        }
        return criterias
    }

    List getPhase() {
        def phases = []
        phaseStr.each {
            phases << it.toInteger()
        }
        return phases
    }

    List getRelativeToSO() {
        def relativeToSo = []
        relativeToSOStr.each {
            relativeToSo << RelativeToSO.fromName(it)
        }
        return relativeToSo
    }

    List getPurchaserCriterias() {
        def criterias = []
        purchaserCriteriaStrs.each {
            criterias << PurchaserCriteria.fromName(it)
        }
        return criterias
    }

    List getOriginOfDivestment() {
        def originOfDivestments = []
        originOfDivestmentStrs.each {
            originOfDivestments << OriginOfDivestment.fromName(it)
        }
        return originOfDivestments
    }
}

